package com.example.swaggerdemo.config;


import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.core.annotation.Order;
import org.springframework.util.StringUtils;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.AuthorizationScopeBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.AuthorizationScope;
import springfox.documentation.service.SecurityReference;
import springfox.documentation.service.SecurityScheme;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

@Configuration
@EnableOpenApi
@ConditionalOnWebApplication
@ConditionalOnClass(Docket.class)
@Profile({ "!prod & !PROD" })
public class BdapSwagger2Config {
	public static final ObjectMapper MAPPER = new ObjectMapper();
	@Autowired
	private SwaggerConfigProperties swaggerConfigProperties;

	@Bean
	@Order(Integer.MAX_VALUE)
	@ConditionalOnMissingBean
	public Docket createRestApi() {
		if (swaggerConfigProperties.getSecurity() == null
				|| swaggerConfigProperties.getSecurity().getReference() == null
				|| swaggerConfigProperties.getSecurity().getReference().isEmpty()
				|| swaggerConfigProperties.getSecurity().getScheme() == null
				|| swaggerConfigProperties.getSecurity().getScheme().isEmpty()) {
			return new Docket(swaggerConfigProperties.getDocumentationType()).apiInfo(apiInfo())
					.pathMapping(
							swaggerConfigProperties.isEnableContextRoot() ? swaggerConfigProperties.getContextRoot() : "")
					.select().apis(RequestHandlerSelectors.basePackage(swaggerConfigProperties.getBasePackage()))
					.paths(PathSelectors.any()).build();
		}
		List<SecurityScheme> securitySchemes = new ArrayList<>();
		for (Entry<String, SwaggerConfigProperties.Scheme> schemeEntry : swaggerConfigProperties.getSecurity().getScheme().entrySet()) {
			SwaggerSecuritySchemeTypeEnum securitySchemeType = SwaggerSecuritySchemeTypeEnum
					.valueOf(schemeEntry.getValue().getType());
			securitySchemes.add(securitySchemeType.getSecurityScheme(schemeEntry.getKey(), schemeEntry.getValue()));
		}
		List<SecurityContext> securityContexts = new ArrayList<>();
		for (Map<String, String> refMap : swaggerConfigProperties.getSecurity().getReference()) {
			List<SecurityReference> securityReferences = new ArrayList<>();
			for (Entry<String, String> ref : refMap.entrySet()) {
				if (!StringUtils.hasLength(ref.getValue()) || "[]".equals(ref.getValue())) {
					securityReferences.add(SecurityReference.builder().reference(ref.getKey())
							.scopes(new AuthorizationScope[0]).build());
					continue;
				}
				try {
					MAPPER.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
					ArrayList readValue = MAPPER.readValue(ref.getValue(), ArrayList.class);
					AuthorizationScope[] scopes = new AuthorizationScope[readValue.size()];
					for (int i = 0; i < readValue.size(); i++) {
						scopes[i] = new AuthorizationScopeBuilder().scope(readValue.get(i).toString()).build();
					}
					securityReferences.add(SecurityReference.builder().reference(ref.getKey()).scopes(scopes).build());
				} catch (Throwable e) {
					securityReferences.add(SecurityReference.builder().reference(ref.getKey())
							.scopes(new AuthorizationScope[0]).build());
				}
			}
			securityContexts.add(SecurityContext.builder().securityReferences(securityReferences).build());
		}
		return new Docket(swaggerConfigProperties.getDocumentationType()).apiInfo(apiInfo())
				.pathMapping(
						swaggerConfigProperties.isEnableContextRoot() ? swaggerConfigProperties.getContextRoot() : "")
				.securitySchemes(securitySchemes).securityContexts(securityContexts).select()
				.apis(RequestHandlerSelectors.basePackage(swaggerConfigProperties.getBasePackage()))
				.paths(PathSelectors.any()).build();
	}

	private ApiInfo apiInfo() {
		return new ApiInfoBuilder().title(swaggerConfigProperties.getTitle())
				.description(swaggerConfigProperties.getDescription())
				// .contact(new Contact("fanl", "#", "862844083@qq.com"))
				.version(swaggerConfigProperties.getVersion()).build();
	}

}